﻿using System;
using System.Runtime.InteropServices;

namespace FortuneUniverse.Fortune.Algorithms
{
  [StructLayout(LayoutKind.Sequential, Size = 1)]
  public struct Mathf
  {
    public const float PI = 3.141593f;
    public const float Infinity = float.PositiveInfinity;
    public const float NegativeInfinity = float.NegativeInfinity;
    public const float Deg2Rad = 0.01745329f;
    public const float Rad2Deg = 57.29578f;

    public static float Sin(float f) => (float) Math.Sin((double) f);

    public static float Cos(float f) => (float) Math.Cos((double) f);

    public static float Tan(float f) => (float) Math.Tan((double) f);

    public static float Asin(float f) => (float) Math.Asin((double) f);

    public static float Acos(float f) => (float) Math.Acos((double) f);

    public static float Atan(float f) => (float) Math.Atan((double) f);

    public static float Atan2(float y, float x) => (float) Math.Atan2((double) y, (double) x);

    public static float Sqrt(float f) => (float) Math.Sqrt((double) f);

    public static float Abs(float f) => Math.Abs(f);

    public static int Abs(int value) => Math.Abs(value);

    public static float Min(float a, float b) => (double) a < (double) b ? a : b;

    public static float Min(params float[] values)
    {
      int length = values.Length;
      float num1;
      if (length == 0)
      {
        num1 = 0.0f;
      }
      else
      {
        float num2 = values[0];
        for (int index = 1; index < length; ++index)
        {
          if ((double) values[index] < (double) num2)
            num2 = values[index];
        }
        num1 = num2;
      }
      return num1;
    }

    public static int Min(int a, int b) => a < b ? a : b;

    public static int Min(params int[] values)
    {
      int length = values.Length;
      int num1;
      if (length == 0)
      {
        num1 = 0;
      }
      else
      {
        int num2 = values[0];
        for (int index = 1; index < length; ++index)
        {
          if (values[index] < num2)
            num2 = values[index];
        }
        num1 = num2;
      }
      return num1;
    }

    public static float Max(float a, float b) => (double) a > (double) b ? a : b;

    public static float Max(params float[] values)
    {
      int length = values.Length;
      float num1;
      if (length == 0)
      {
        num1 = 0.0f;
      }
      else
      {
        float num2 = values[0];
        for (int index = 1; index < length; ++index)
        {
          if ((double) values[index] > (double) num2)
            num2 = values[index];
        }
        num1 = num2;
      }
      return num1;
    }

    public static int Max(int a, int b) => a > b ? a : b;

    public static int Max(params int[] values)
    {
      int length = values.Length;
      int num1;
      if (length == 0)
      {
        num1 = 0;
      }
      else
      {
        int num2 = values[0];
        for (int index = 1; index < length; ++index)
        {
          if (values[index] > num2)
            num2 = values[index];
        }
        num1 = num2;
      }
      return num1;
    }

    public static float Pow(float f, float p) => (float) Math.Pow((double) f, (double) p);

    public static float Exp(float power) => (float) Math.Exp((double) power);

    public static float Log(float f, float p) => (float) Math.Log((double) f, (double) p);

    public static float Log(float f) => (float) Math.Log((double) f);

    public static float Log10(float f) => (float) Math.Log10((double) f);

    public static float Ceil(float f) => (float) Math.Ceiling((double) f);

    public static float Floor(float f) => (float) Math.Floor((double) f);

    public static float Round(float f) => (float) Math.Round((double) f);

    public static int CeilToInt(float f) => (int) Math.Ceiling((double) f);

    public static int FloorToInt(float f) => (int) Math.Floor((double) f);

    public static int RoundToInt(float f) => (int) Math.Round((double) f);

    public static float Sign(float f) => (double) f >= 0.0 ? 1f : -1f;

    public static float Clamp(float value, float min, float max)
    {
      if ((double) value < (double) min)
        value = min;
      else if ((double) value > (double) max)
        value = max;
      return value;
    }

    public static int Clamp(int value, int min, int max)
    {
      if (value < min)
        value = min;
      else if (value > max)
        value = max;
      return value;
    }

    public static float Clamp01(float value) => (double) value >= 0.0 ? ((double) value <= 1.0 ? value : 1f) : 0.0f;

    public static float Lerp(float a, float b, float t) => a + (b - a) * Mathf.Clamp01(t);

    public static float LerpUnclamped(float a, float b, float t) => a + (b - a) * t;

    public static float LerpAngle(float a, float b, float t)
    {
      float num = Mathf.Repeat(b - a, 360f);
      if ((double) num > 180.0)
        num -= 360f;
      return a + num * Mathf.Clamp01(t);
    }

    public static float MoveTowards(float current, float target, float maxDelta) => (double) Mathf.Abs(target - current) > (double) maxDelta ? current + Mathf.Sign(target - current) * maxDelta : target;

    public static float MoveTowardsAngle(float current, float target, float maxDelta)
    {
      float num1 = Mathf.DeltaAngle(current, target);
      float num2;
      if (-(double) maxDelta < (double) num1 && (double) num1 < (double) maxDelta)
      {
        num2 = target;
      }
      else
      {
        target = current + num1;
        num2 = Mathf.MoveTowards(current, target, maxDelta);
      }
      return num2;
    }

    public static float SmoothStep(float from, float to, float t)
    {
      t = Mathf.Clamp01(t);
      t = (float) (-2.0 * (double) t * (double) t * (double) t + 3.0 * (double) t * (double) t);
      return (float) ((double) to * (double) t + (double) from * (1.0 - (double) t));
    }

    public static float Repeat(float t, float length) => Mathf.Clamp(t - Mathf.Floor(t / length) * length, 0.0f, length);

    public static float PingPong(float t, float length)
    {
      t = Mathf.Repeat(t, length * 2f);
      return length - Mathf.Abs(t - length);
    }

    public static float InverseLerp(float a, float b, float value) => (double) a == (double) b ? 0.0f : Mathf.Clamp01((float) (((double) value - (double) a) / ((double) b - (double) a)));

    public static float DeltaAngle(float current, float target)
    {
      float num = Mathf.Repeat(target - current, 360f);
      if ((double) num > 180.0)
        num -= 360f;
      return num;
    }

    internal static bool LineIntersection(
      Vector2 p1,
      Vector2 p2,
      Vector2 p3,
      Vector2 p4,
      ref Vector2 result)
    {
      float num1 = p2.x - p1.x;
      float num2 = p2.y - p1.y;
      float num3 = p4.x - p3.x;
      float num4 = p4.y - p3.y;
      float num5 = (float) ((double) num1 * (double) num4 - (double) num2 * (double) num3);
      bool flag;
      if ((double) num5 == 0.0)
      {
        flag = false;
      }
      else
      {
        double num6 = (double) p3.x - (double) p1.x;
        float num7 = p3.y - p1.y;
        double num8 = (double) num4;
        float num9 = (float) (num6 * num8 - (double) num7 * (double) num3) / num5;
        result = new Vector2(p1.x + num9 * num1, p1.y + num9 * num2);
        flag = true;
      }
      return flag;
    }

    internal static bool LineSegmentIntersection(
      Vector2 p1,
      Vector2 p2,
      Vector2 p3,
      Vector2 p4,
      ref Vector2 result)
    {
      float num1 = p2.x - p1.x;
      float num2 = p2.y - p1.y;
      float num3 = p4.x - p3.x;
      float num4 = p4.y - p3.y;
      float num5 = (float) ((double) num1 * (double) num4 - (double) num2 * (double) num3);
      bool flag;
      if ((double) num5 == 0.0)
      {
        flag = false;
      }
      else
      {
        float num6 = p3.x - p1.x;
        float num7 = p3.y - p1.y;
        float num8 = (float) ((double) num6 * (double) num4 - (double) num7 * (double) num3) / num5;
        if ((double) num8 < 0.0 || (double) num8 > 1.0)
        {
          flag = false;
        }
        else
        {
          float num9 = (float) ((double) num6 * (double) num2 - (double) num7 * (double) num1) / num5;
          if ((double) num9 < 0.0 || (double) num9 > 1.0)
          {
            flag = false;
          }
          else
          {
            result = new Vector2(p1.x + num8 * num1, p1.x + num8 * num2);
            flag = true;
          }
        }
      }
      return flag;
    }
  }
}
